mod imports;
mod game;
mod engine;

use wasm_bindgen::prelude::*;
use js_sys;
use console_error_panic_hook;

use crate::game::{Loc,Piece,Board};
#[allow(unused_imports)]
use crate::imports::js;

#[wasm_bindgen]
pub fn sslash_init(js_fn_call:&js_sys::Function) -> JsValue {
    console_error_panic_hook::set_once();
    let fn_call = |name:&str, value:&str| {
        let a = JsValue::from_str(name);
        let b = JsValue::from_str(value);
        js_fn_call.call2(&JsValue::null(), &a, &b).unwrap();
    };
    if ! engine::init(fn_call) {return JsValue::FALSE}
    let str = format!("[NOW] WASM HAS BE NOT EASYLY (ver-{})", env!("SSLASH_VERSION"));
    JsValue::from_str(&str)
}

#[wasm_bindgen]
pub fn sslash_gc() {
    engine::gc();
}

#[wasm_bindgen]
pub fn sslash_set(name:&str, val:&JsValue) -> bool {
    match name {
        "uct-times" => {
            engine::params::set_uct_times(val.as_f64().unwrap_or(0f64) as usize)
        }
        "level" => {
            engine::params::set_level(val.as_f64().unwrap_or(0f64) as usize)
        }
        _ => {false}
    }
}

fn make_piece_from_str(a:&str) -> Piece {
    match &a[0..1] {
        "b" | "B" => {Piece::Black}
        "w" | "W" => {Piece::White}
        _ => {Piece::Empty}
    }
}

fn make_board_from_str(a:&str) -> Board {
    fn set_board(board:&mut Board, loc:Loc, p:Piece, n:usize) -> Loc {
        if n > 0 {
            board.set(loc, p);
            set_board(board, 1+loc, p, n-1)
        } else {loc}
    }
    let mut board = Board::default();
    let mut i = 0;
    let b:Vec<&str> = a.split('|').collect();
    for part in b {
        let p = make_piece_from_str(part);
        let n = usize::from_str_radix(&part[1..], 10).unwrap_or(0);
        i = set_board(&mut board, i, p, n);
    }
    board
}

#[wasm_bindgen]
pub fn sslash_step(pcur_str:&str, board_str:&str, fn_report:&js_sys::Function, fn_say:&js_sys::Function) -> Box<[JsValue]> {
    let mut moves:Vec<JsValue> = vec![];
    let pcur = make_piece_from_str(pcur_str);
    let board = make_board_from_str(board_str);
    let fn_yield = |a:&str| {
        let a = JsValue::from_str(a);
        fn_report.call1(&JsValue::null(), &a).unwrap();
    };
    let fn_say = |a:&str| {
        let a = JsValue::from_str(a);
        fn_say.call1(&JsValue::null(), &a).unwrap();
    };
    if pcur != Piece::Empty {
        for loc in engine::step(pcur, &board, fn_yield, fn_say) {
            moves.push(JsValue::from(loc));
        }
    }
    moves.into_boxed_slice()
}
